//=============================================================================
// TestGameApp GP1 by Bart Uyttenhove
//=============================================================================
#include "StdAfx.h"
#include "TestGameApp.h"
#include "PhysX.h"
#include "ContentManager.h"
#include "InputStateManager.h"
#include "RenderContext.h"
#include "Level.h"
#include "GraphCamera.h"
#include "Sphere.h"
#include "TrianglePosColor.h"
#include "QuadPosColor.h"

#include "ObjMesh.h"
#include "CubePhysX.h"
#include "Character.h"
#include "PickableItem.h"

#define _USE_MATH_DEFINES
#include "math.h"
#include "meshtoobjwriter.h"
#include "PhysicsMesh.h"
#include "PhysicsDebugRenderer.h"
#include "Door.h"
#include "DX10ObjMesh.h"
#include "weapons/Glock.h"
#include "Monster.h"
#include "AmmoCrate.h"
#include "SkyBox.h"
#include "FullscreenQuad.h"
#include "Terrain.h"
#include "FullScreenPostProcess.h"
#include "ParticleSystem.h"
#include "Tornado.h"
#include "Tree.h"
#include "Cube.h"

#include <math.h>
#include <boost/foreach.hpp>
#include "Key.h"

TestGameApp::TestGameApp(HINSTANCE hInstance)
	: D3DApp(hInstance)
	,m_pPhysX(0)
	,m_pLevel(0)
	,m_pGraphCamera(0)
	,m_pCharacter(0)
	,m_pSphere(0)
	,m_pTrianglePosColor(0)
	,m_pQuadPosColor(0)
	,m_Angle(0)
	,m_SkyBoxPtr(0)
	,m_FullScreenQuad(0)
	,m_pTerrain(0)
	,mShadowMap(0)
	,m_PostProcess(0)
	,m_PostPorcessQuad(0)
	,m_pOrthoCamera(0)
	,AngleUp(0)
	,AnglePitch(0.59999985f)
	,m_Tornado(0)
{

}

TestGameApp::~TestGameApp()
{
	SafeDelete(m_pLevel);
	SafeDelete(m_pPhysX);
	SafeDelete(m_FullScreenQuad);
	SafeDelete(m_PostProcess);
	SafeDelete(mShadowMap);
	Tree::ReleaseDrawMesh();
}

void TestGameApp::InitApp()
{

	// direction updated at runtime
	m_DirLight.ambient  = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
	m_DirLight.diffuse  = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	m_DirLight.specular = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);

	D3DXVECTOR3 lightPos;
	lightPos.x = 30.0f;
	lightPos.y = 20.0f;
	lightPos.z = 30.0f;

	D3DXVECTOR3 lightDirection(-0.88935286f, 0.45721933f, 0.0014213272f);

	D3DXMatrixLookAtLH(&mLightView, &lightPos,
		&lightDirection, &D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	
	//D3DXVECTOR3 lightDirection(0.5f, 0.5f, 0.5f);
	D3DXVec3Normalize(&m_DirLight.dir, &lightDirection);

	//hoek tussen X en Z as
	float AngleXZ = atan2(-m_DirLight.dir.z, -m_DirLight.dir.x);// * 180 / M_PI;
	float AngleXY = atan2(-m_DirLight.dir.y, -m_DirLight.dir.x);// * 180 / M_PI;

	float test = static_cast<float>(atan2(10.0, -10.0) * 180 / M_PI);
                        //float Hoekje = (float)(Angle2 * (180 / Math.PI));
	//Hoek tussen X en Y as

	//choose window title
	m_MainWndCaption = L"D3D10 Test Application";
	D3DApp::InitApp();


	m_pPhysX = new PhysX();
	m_pPhysX->Init();

	m_pLevel = new Level(m_pD3DDevice, m_pPhysX);

		//Shadow mapping stuff
	BuildShadowMapFX = m_pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/buildshadowmap.fx"));
	DrawShadowMapFX  = m_pContentManager->GetEffect(m_pLevel->GetDevice(), _T("./Effect/drawshadowmap.fx"));
	//ShadowFX         = m_pContentManager->GetEffect(m_pLevel->GetDevice(), _T("./Effect/shadow.fx"));

	mfxBuildShadowMapDiffuseMapVar = BuildShadowMapFX->GetVariableByName("gDiffuseMap")->AsShaderResource();
	mfxBuildShadowMapLightWVPVar   = BuildShadowMapFX->GetVariableByName("gLightWVP")->AsMatrix();

	mBuildShadowMapTech = BuildShadowMapFX->GetTechniqueByName("BuildShadowMapTech");
	

	mfxDrawShadowMapTexVar = DrawShadowMapFX->GetVariableByName("gShadowMap")->AsShaderResource();
	mDrawShadowMapTech = DrawShadowMapFX->GetTechniqueByName("DrawShadowMapTech");

	//mfxShadowMapVar = ShadowFX->GetVariableByName("gShadowMap")->AsShaderResource();

	mFloorMapRV = m_pContentManager->GetTexture(m_pLevel->GetDevice(), _T("./bitmaps/floor_diffuse.dds"));

	mShadowMap = new DrawableTex2D(m_pLevel->GetDevice());
	mShadowMap->Init(2048, 2048, false, DXGI_FORMAT_UNKNOWN);
	
	//End shadowmapping stuff

	m_pGraphCamera = new GraphCamera(m_ClientWidth, m_ClientHeight);
	m_pGraphCamera->Move(D3DXVECTOR3(154.63554f,-508.95950f,353.82373f), true, 0.59999985f, 0.88999963f);
	m_pGraphCamera->SetOrthographicView(false, NULL);

	m_pOrthoCamera = new GraphCamera(790, 790, 300.0f, 850.0f);
	m_pOrthoCamera->LookAt(m_DirLight.pos, m_DirLight.pos-m_DirLight.dir, D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	//m_pOrthoCamera->LookAt2(m_DirLight.pos, m_DirLight.dir, m_DirLight.
	//m_pOrthoCamera->Move(D3DXVECTOR3(30,20,30), true, 0.59999985f, 0.88999963f);
	//m_pOrthoCamera->Move(D3DXVECTOR3(30,20,30), true, m_DirLight.dir.y, m_DirLight.dir.z);
	m_pOrthoCamera->SetOrthographicView(true, m_pGraphCamera);
	m_pOrthoCamera->IsActive(false);

	//m_pGraphCamera->LookAt(D3DXVECTOR3(30,20,30),D3DXVECTOR3(-0.5f, -0.7f, 0.0f),D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	//m_pGraphCamera->Rotate(D3DXVECTOR3(0.707f, -0.707f, 0.0f));
	//m_pGraphCamera->LookAt(D3DXVECTOR3(30,20,30),D3DXVECTOR3(0,-2,0),D3DXVECTOR3(0,1,0));

	//m_OrthoCamera->LookAt(D3DXVECTOR3(30,20,30),D3DXVECTOR3(0.707f, -0.707f, 0.0f),D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	//m_pLevel->AddChild(m_pGraphCamera);
	
	m_pCharacter = new Character(m_pGraphCamera,D3DXVECTOR3(154.63554f,-506.95950f,353.82373f),m_pPhysX);
	m_pLevel->AddChild(m_pCharacter);

	// Load concave model
	//PhysicsMesh *concavemesh = new PhysicsMesh(_T("./Models/level.obj"), _T("./Models/level.concavebin"), float3(0,0,0), float3(-1.57079633f,0,0),PhysicsMesh::Concave, m_pPhysX);
	//concavemesh->Translate(D3DXVECTOR3(0,0,0));
	//m_pLevel->AddChild(concavemesh);

	//// Load convex model
	//PhysicsMesh *convexmesh = new PhysicsMesh(_T("./Models/box.obj"), _T("./Models/box.convexbin"),float3(0,0,0), float3(-1.57079633f,0,0), PhysicsMesh::Convex, m_pPhysX);
	//convexmesh->Translate(D3DXVECTOR3(0,-20,0));
	//m_pLevel->AddChild(convexmesh);

	// Load key
	//m_pSphere = new Sphere(_T("./textures/DAE_logo_high_whiteBg.dds"),1);
	//PickableItem* item = new PickableItem(m_pPhysX,1,D3DXVECTOR3(21.3f,5.5f,20.0f),m_pSphere,true);
	//m_pLevel->AddChild(item);

	
	//PhysicsDebugRenderer* renderer = new PhysicsDebugRenderer(m_pPhysX);
	//m_pLevel->AddChild(renderer);

	ParticleSystem* rain = new ParticleSystem(ParticleSystem::Rain,  float3(154.63554f,-508.95950f,353.82373f),m_pGraphCamera);
	rain->SetName(L"ParticleSystem");	
	m_pLevel->AddChild(rain);

	//Initialize all child objects
	m_pLevel->Initialize(m_pContentManager, m_pGraphCamera);

	//Weapon info
	m_Weapon = new Glock(m_pLevel);
	m_Weapon->SetCharacter(m_pCharacter);
	m_pLevel->AddChild(m_Weapon);

	//Door
	Door* door = new Door(m_pLevel, D3DXVECTOR3(144.0f,-506.0f,353.0f), 0.0f, this);
	door->Initialize(m_pContentManager);
	m_pLevel->AddChild(door);

	//Ammobox
	AmmoCrate* ammoCrate = new AmmoCrate(m_pLevel,m_pPhysX,D3DXVECTOR3(156.63554f,-508.0f,353.82373f), true, this);
	ammoCrate->Initialize(m_pContentManager);
	m_pLevel->AddChild(ammoCrate);

	//Key
	Key* key = new Key(m_pLevel,m_pPhysX,1,D3DXVECTOR3(150.0f,-508.0f,353.82373f), true, this);
	key->Initialize(m_pContentManager);
	m_pLevel->AddChild(key);

	//Trees
	Tree::BuildDrawMesh(this,m_pLevel, m_pContentManager);
	Tree* tree = new Tree(D3DXVECTOR3(150.0f,-509.0f,373.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(140.0f,-509.0f,363.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(140.0f,-509.0f,343.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(160.0f,-509.0f,363.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(120.0f,-509.0f,333.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);


	tree = new Tree(D3DXVECTOR3(170.0f,-509.0f,383.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(150.0f,-509.0f,393.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	tree = new Tree(D3DXVECTOR3(130.0f,-509.0f,393.82373f), this);
	tree->Initialize(m_pContentManager);
	m_pLevel->AddChild(tree);

	//SkyBox
	m_SkyBoxPtr = new SkyBox(m_pLevel, _T("./bitmaps/grassenvmap1024.dds"));
	m_SkyBoxPtr->Initialize(m_pContentManager);
	m_pLevel->AddChild(m_SkyBoxPtr);

	m_FullScreenQuad = new FullscreenQuad(_T("./bitmaps/grassenvmap1024.dds"), m_pLevel);
	m_FullScreenQuad->Initialize(m_pContentManager);
	m_FullScreenQuad->SetTexture(mShadowMap->GetDepthMap());

	//Post process part
	m_PostPorcessQuad = new FullScreenPostProcess(_T("./bitmaps/grassenvmap1024.dds"), m_pLevel);
	m_PostPorcessQuad->Initialize(m_pContentManager);
	//
	////Bloom post process
	m_PostProcess = new DrawableTex2D(m_pLevel->GetDevice());
	m_PostProcess->Init(m_ClientWidth, m_ClientHeight, true, DXGI_FORMAT_R8G8B8A8_UNORM);
	m_PostPorcessQuad->SetTexture(m_PostProcess->GetColorMap());

	m_Cube = new Cube(m_pLevel);
	m_Cube->Initialize(m_pContentManager);
	m_Cube->Translate(D3DXVECTOR3( 174.13545, -507.15967, 335.87540));
	m_pLevel->AddChild(m_Cube);

	//Tornado
	//m_Tornado = new Tornado(m_pPhysX, NxVec3( 174.13545, -507.15967, 335.87540));
	//m_Tornado->Setup();

	//m_pLevel->AddChild(m_Tornado);

	//Initializing Terrain data
	Terrain::InitInfo tii;
	tii.HeightmapFilename = L"./Bitmaps/Valley2.raw";
	tii.LayerMapFilename0 = L"./Bitmaps/grass.dds";
	tii.LayerMapFilename1 = L"./Bitmaps/lightdirt.dds";
	tii.LayerMapFilename2 = L"./Bitmaps/darkdirt.dds";
	tii.LayerMapFilename3 = L"./Bitmaps/stone.dds";
	tii.LayerMapFilename4 = L"./Bitmaps/snow.dds";
	tii.BlendMapFilename  = L"./Bitmaps/blend2.dds";
	tii.HeightScale  = 0.0015f;
	tii.HeightOffset = -513.0f;
	tii.NumRows      = 513;
	tii.NumCols      = 513;
	tii.CellSpacing  = 1.0f;
	tii.CastShadows = true;

	m_pTerrain = new Terrain(m_pLevel, tii);
	m_pTerrain->Initialize(m_pContentManager);
	m_pLevel->AddChild(m_pTerrain);

	D3DXVECTOR3 max;
	D3DXVECTOR3 min;
	max.x = -1000.0f;
	max.y = -1000.0f;
	max.z = -1000.0f;

	min.x = 1000.0f;
	min.y = 1000.0f;
	min.z = 1000.0f;

	
	//Doorloop al de vectireces in lightspace en zoek min en max values
	/*BOOST_FOREACH(VertexPosNormTex& vertex, m_pTerrain->GetVextexList())
	{
		D3DXVECTOR4 current;
		D3DXVec3Transform(&current, &vertex.pos, &m_pOrthoCamera->GetViewProj());

		current.x /= current.w;
		current.y /= current.w;
		current.z /= current.w;

		if(current.x > max.x)
			max.x = current.x;
		if(current.x < min.x)
			min.x = current.x;
		if(current.y > max.y)
			max.y = current.y;
		if(current.y < min.y)
			min.y = current.y;
		if(current.z > max.z)
			max.z = current.z;
		if(current.z < min.z)
			min.z = current.z;
	}*/


	Monster* ryzoholok = new Monster(m_pLevel, L"Models/Monsters/girl.obj", L"Models/Monsters/monster1.concavebin", float3(154.63554f,-508.95950f,353.82373f),float3(-3.14f/2,0,0),m_pPhysX, this, m_pCharacter);
	ryzoholok->Initialize(m_pContentManager);
	m_pLevel->AddChild(ryzoholok);
	//Initialize game model data
	IniFile* config = new IniFile();
	config->SetValue(_T("Export"),_T("baseDir"),_T("."));
	config->SetValue(_T("Export"),_T("meshDir"),_T(""));
	config->SetValue(_T("Export"),_T("textureDir"),_T(""));
	config->SetValue(_T("Export"),_T("skeletonDir"),_T(""));
	
	this->LoadObjMesh(config, L"Models/Weapons/Glock/Glock.obj");

}

void TestGameApp::OnResize()
{
	D3DApp::OnResize();
	//OnResize is called before level exists
	if(m_pLevel)m_pLevel->OnResize(m_ClientWidth, m_ClientHeight);
	//if(m_DrawableTex2D != 0)
	//{
	//	SafeDelete(m_DrawableTex2D);
	//	m_DrawableTex2D = new DrawableTex2D(m_pLevel->GetDevice());
	//	m_DrawableTex2D->Init(m_ClientWidth, m_ClientHeight, true, DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM);
	//	m_FullScreenQuad->SetTexture(m_DrawableTex2D->GetColorMap());
	//}
}
void TestGameApp::KeyPressed(WPARAM key)
{
	switch (key)
	{
		case 'C':
			m_pOrthoCamera->ToggleCropMatrix();
			return;
	}
}
void TestGameApp::UpdateScene(const InputState & refInputState)
{
	D3DApp::UpdateScene(refInputState);

	D3DXVECTOR3 dir(0.0f, 0.0f, 0.0f);

	//test.x = 0.001f;
	//test.y -= 0.1f;
	//m_pGraphCamera->Rotate(test);

	//m_OrthoCamera->LookAt(mLightPos,D3DXVECTOR3(0.0f, 0.0f, 0.0f),D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	//m_OrthoCamera->Set
	//end shadow mapping stuff
	//wait for physx to finish, then get proceed
	m_pPhysX->FetchResults();

	//pass input state to graph
	m_pLevel->Tick(refInputState);

	float dTime = refInputState.GetDeltaTime();
	if(dTime>0.3)dTime=0.2f;//prevent dTime from getting too large
	m_Angle+=6.28f/4*dTime;

	//laat physics volgende stap berekenen in thread
	m_pPhysX->Simulate(dTime);

	m_Weapon->Tick(refInputState);
	m_pOrthoCamera->Tick(refInputState);
	//m_pOrthoCamera->ResetWorldMatrix();
	//m_pOrthoCamera->Move(D3DXVECTOR3(0,0,0), true, 0.0f, 0.0001f);
	//AnglePitch += 0.01f;
	//zorgt ervoor dat de muis in het midden blijft
	//SetCursorPos(m_ClientWidth / 2, m_ClientHeight / 2);
}

void TestGameApp::DrawScene()
{
	//m_DrawableTex2D->Begin();
	mShadowMap->Begin();

	drawSceneToShadowMap();

	mShadowMap->End();

	ResetRenderTargets();

	RenderContext renderContext(m_pGraphCamera, m_DirLight);
	////Post processing BLOOM
	//RenderContext renderContext(m_pGraphCamera, m_DirLight);
	m_PostProcess->Begin();
	m_pLevel->Draw(&renderContext, mShadowMap->GetDepthMap());
	m_PostProcess->End();

	ResetRenderTargets();
	m_PostPorcessQuad->Draw(&renderContext);
	/////Einde

	//m_DrawableTex2D->End();
	//ResetRenderTargets();
	//Shadow map render
	//m_FullScreenQuad->SetTexture(mShadowMap->GetDepthMap());
	//m_FullScreenQuad->Draw(&renderContext);
	//draw statistics
	D3DApp::DrawScene();
}
void TestGameApp::ResetRenderTargets()
{
	m_pD3DDevice->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);
	
	D3D10_VIEWPORT vp;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	vp.Width    = m_ClientWidth;
	vp.Height   = m_ClientHeight;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;

	m_pD3DDevice->RSSetViewports(1, &vp);

}
void TestGameApp::drawSceneToShadowMap()
{
	m_pLevel->DrawShadowMap(m_pOrthoCamera, mLightView, BuildShadowMapFX);
}
void TestGameApp::LoadObjMesh(IniFile* config,wstring loc)
{
	ObjReader reader(config,loc);
	if ( reader.Read() )
	{
		MeshList* list = new MeshList();
		reader.CopyIntoMeshList(list);
		vector<ObjMesh*>::const_iterator it;
		for (it=list->begin(); it!= list->end(); it++)
		{
			ObjMesh* mesh = *it;
			// standaard shader meegeven
			DX10ObjMesh* dx10Mesh = Compile(mesh,_T("NormalMap.fx"), _T("checkertech"));
			if ( dx10Mesh != 0 )
			{
				float radialen = -1.570796327f;
				dx10Mesh->ResetWorldMatrix();
				dx10Mesh->Rotate(D3DXVECTOR3(radialen,0,0));
				dx10Mesh->Translate(D3DXVECTOR3(0,4,0));
				m_pLevel->AddChild(dx10Mesh);
			}
			m_Weapon->SetWeaponMesh(dx10Mesh);
		}
	}
}

